package jmind.core.manager;

import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import jmind.core.lang.IProperties;
import jmind.core.util.DataUtil;

import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.Mongo;
import com.mongodb.MongoException;
import com.mongodb.MongoOptions;
import com.mongodb.ServerAddress;
import com.mongodb.util.JSON;

public abstract class AbstractMongoManager {

    private final String MONGO_PREFIX = "mongo.";

    private final Map<String, DB> dbs = new ConcurrentHashMap<String, DB>();

    public abstract IProperties getProperties();

    public DB getResource(final String name) {
        DB db = dbs.get(name);
        if (db == null) {
            synchronized (dbs) {
                if (dbs.containsKey(name)) {
                    return dbs.get(name);
                } else {
                    db = initDB(name);
                    dbs.put(name, db);
                }
            }

        }
        return db;
    }

    private DB initDB(String name) {
        Mongo mongo;
        DB db = null;
        try {
            String configs = getProperties().getProperty(MONGO_PREFIX + name);
            System.out.println(configs);
            BasicDBObject config = (BasicDBObject) JSON.parse(configs);
            MongoOptions options = new MongoOptions();
            if (config.containsField("options")) {
                BasicDBObject option = (BasicDBObject) config.get("options");
                if (option.containsField("autoConnectRetry")) {
                    options.autoConnectRetry = option.getBoolean("autoConnectRetry"); //true
                }
                if (option.containsField("socketKeepAlive")) {
                    options.socketKeepAlive = option.getBoolean("socketKeepAlive"); // true
                }
                if (option.containsField("connectionsPerHost")) {
                    options.connectionsPerHost = option.getInt("connectionsPerHost"); //20
                }
                if (option.containsField("maxWaitTime")) {
                    options.maxWaitTime = option.getInt("maxWaitTime"); //120000
                }
                if (option.containsField("socketTimeout")) {
                    options.socketTimeout = option.getInt("socketTimeout"); // 5000
                }
                if (option.containsField("connectTimeout")) {
                    options.connectTimeout = option.getInt("connectTimeout"); //1000
                }
                if (option.containsField("threadsMultiplier")) {
                    options.threadsAllowedToBlockForConnectionMultiplier = option.getInt("threadsMultiplier"); // 10
                }
            }
            String host = config.getString("host");
            if (host.contains(",")) {
                String[] hosts = host.split(",");
                List<ServerAddress> replicaSetSeeds = new ArrayList<ServerAddress>();
                for (String h : hosts) {
                    replicaSetSeeds.add(new ServerAddress(h));
                }
                mongo = new Mongo(replicaSetSeeds, options);
            } else {
                mongo = new Mongo(host, options);
            }

            db = mongo.getDB(config.getString("db"));
            if (config.containsField("auth")) { // 权限验证
                BasicDBObject auth = (BasicDBObject) config.get("auth");
                db.authenticate(auth.getString("user"), auth.getString("pwd").toCharArray());
            }
        } catch (UnknownHostException e) {

            e.printStackTrace();
        } catch (MongoException e) {

            e.printStackTrace();
        }
        return db;
    }

    public DBCollection getSimpleColl(String uri) {
        DBCollection coll = null;
        try {
            String[] config = uri.split("#");
            Mongo mongo = new Mongo(config[0]);
            DB db = mongo.getDB(config[1]);
            coll = db.getCollection(config[2]);
        } catch (UnknownHostException e) {

            e.printStackTrace();
        } catch (MongoException e) {
            e.printStackTrace();
        }

        return coll;
    }

    /**
     * 
     * @param dbName
     * @param table
     * @param query {"uid":45346616}
     * @param sort  {"_id":1}
     * @param start
     * @param limit
     * @return
     */
    public List<DBObject> find(String dbName, String table, String query, String sort, int start, int limit) {
        DB db = getResource(dbName);
        DBCollection coll = db.getCollection(table);
        DBObject ref = DataUtil.isEmpty(query) ? null : (DBObject) JSON.parse(query);
        DBCursor find = coll.find(ref);
        if (!DataUtil.isEmpty(sort)) {
            DBObject osort = (DBObject) JSON.parse(sort);
            find = find.sort(osort);
        }
        return find.skip(start).limit(limit).toArray();
    }

    /**
     * 
     * 2013-7-3 
     * @param dbName
     * @param table
     * @param obj json 格式
     */
    public void save(String dbName, String table, String obj) {
        DBObject jo = (DBObject) JSON.parse(obj);
        save(dbName, table, jo);
    }

    public void save(String dbName, String table, DBObject jo) {
        DB db = getResource(dbName);
        DBCollection coll = db.getCollection(table);
        coll.save(jo);
    }

    public void insert(String dbName, String table, Map<?, ?> map) {
        DB db = getResource(dbName);
        DBCollection coll = db.getCollection(table);
        coll.insert(new BasicDBObject(map));
    }

    public void insert(String dbName, String table, DBObject... jo) {
        DB db = getResource(dbName);
        DBCollection coll = db.getCollection(table);
        coll.insert(jo);
    }

}
